package com.start.common.user;

import com.alibaba.fastjson2.JSONObject;
import com.start.common.details.BaseUserDetails;
import com.start.common.entity.StartBaseEntity;
import com.start.common.entity.StartBaseUser;
import com.start.common.entity.StartDicData;
import com.start.common.event.StartBaseEvent;
import com.start.common.exceptions.StartBusException;
import com.start.common.tools.SpringContextTools;
import lombok.extern.slf4j.Slf4j;

import java.io.Serializable;
import java.util.*;
import java.util.stream.Collectors;

@Slf4j
public class StartUserInfoLoadService implements StartBaseEvent {
    private static Map<String, UserManageInfoService> userManageInfoServiceMap;

    private static StartUserInfoLoadService userInfoLoadService;

    public static StartUserInfoLoadService getInstance() {
        if (userInfoLoadService == null) {
            userInfoLoadService = new StartUserInfoLoadService();
        }
        if (userManageInfoServiceMap == null) {
            synchronized (StartUserInfoLoadService.class) {
                if (userManageInfoServiceMap == null) {
                    Map<String, UserManageInfoService> beans = SpringContextTools.getBeans(UserManageInfoService.class, false);
                    if (beans == null || beans.isEmpty()) {
                        userManageInfoServiceMap = new HashMap<>();
                    } else {
                        userManageInfoServiceMap = beans.values()
                                .stream()
                                .collect(
                                        Collectors
                                                .toMap(UserManageInfoService::getLoadUserType,
                                                        value -> value,
                                                        (key1, key2) -> key2));
                    }
                }
            }
        }
        return userInfoLoadService;
    }

    /**
     * 获取用户信息加载服务
     *
     * @param startUserType
     * @return
     */
    public UserManageInfoService getUserInfoService(String startUserType) {
        if (userManageInfoServiceMap == null) {
            log.error("userManageInfoServiceMap is  null ");
            return null;
        }
        UserManageInfoService userManageInfoService = userManageInfoServiceMap.getOrDefault(startUserType, null);
        if (userManageInfoService == null) {
            log.error("未找到指定类型的用户加载器：" + startUserType);
        }
        return userManageInfoService;
    }

    /**
     * 根据用户体系以及用户id加载用户信息
     *
     * @param startUserType 用户体系
     * @param userId        用户id
     * @param <T>
     * @return
     */
    public <T extends StartBaseUser> T getUserById(String startUserType, String userId) {
        UserManageInfoService userInfoService = getUserInfoService(startUserType);
        if (userInfoService == null) {
            return null;
        }
        StartBaseUser startBaseUser = userInfoService.getByUserId(userId);
        if (startBaseUser == null) return null;
        return (T) startBaseUser;
    }

    /**
     * 获取用户
     *
     * @param startUserKey
     * @param <T>
     * @return
     */
    public <T extends StartBaseUser> T getUserByStartUserKey(String startUserKey) {
        if (!startUserKey.contains(":")) {
            throw new StartBusException("无效startUserKey:" + startUserKey);
        }
        String[] split = startUserKey.split(":");
        return getUserById(split[0], split[1]);
    }

    /**
     * 获取多个用户
     *
     * @param userKeys 多个 userKey
     * @param <T>
     * @return
     */
    public <T extends StartBaseUser> Map<String, Map<String, T>> getUsersMap(Collection<String> userKeys) {
        Map<String, Map<String, T>> result = new HashMap<>();
        if (userKeys.isEmpty()) return result;
        Map<String, List<String>> userKeyMap = userKeys.stream().distinct().filter(e -> e.contains(":")).collect(Collectors.groupingBy(e -> e.split(":")[0], Collectors.mapping(e -> e.split(":")[1], Collectors.toList())));
        if (userKeyMap.isEmpty()) return result;
        for (String startUserType : userKeyMap.keySet()) {
            List<T> users = getByUserIds(startUserType, userKeyMap.get(startUserType));
            if (users == null) {
                continue;
            }
            Map<String, T> map = users.stream().collect(Collectors.toMap(StartBaseEntity::getId, e -> e));
            result.put(startUserType, map);
        }
        return result;
    }

    public <T extends StartBaseUser> List<T> getUsers(Collection<String> userKeys) {
        List<T> result = new ArrayList<>();
        Map<String, List<String>> userKeyMap = userKeys.stream().distinct().filter(e -> e.contains(":")).collect(Collectors.groupingBy(e -> e.split(":")[0], Collectors.mapping(e -> e.split(":")[1], Collectors.toList())));
        if (userKeys.isEmpty()) {
            return result;
        }
        for (String startUserType : userKeyMap.keySet()) {
            List<T> users = getByUserIds(startUserType, userKeyMap.get(startUserType));
            if (users == null) {
                continue;
            }
            result.addAll(users);
        }
        return result;
    }

    /**
     * 获取多个用户
     *
     * @param userKeys 多个 userKey
     * @param <T>
     * @return
     */
    public <T extends StartBaseUser> Map<String, T> getUsersGroupByUserKey(Collection<String> userKeys) {
        Map<String, T> result = new HashMap<>();
        if (userKeys.isEmpty()) return result;
        Map<String, List<String>> userKeyMap = userKeys.stream().filter(e -> e.contains(":")).collect(Collectors.groupingBy(e -> e.split(":")[0], Collectors.mapping(e -> e.split(":")[1], Collectors.toList())));
        if (userKeyMap.isEmpty()) return result;
        for (String startUserType : userKeyMap.keySet()) {
            UserManageInfoService userInfoService = getUserInfoService(startUserType);
            if (userInfoService == null) {
                continue;
            }
            List<T> byUserIds = userInfoService.getByUserIds(userKeyMap.get(startUserType));
            if (byUserIds == null) return null;
            for (Object o : byUserIds) {
                T user = (T) o;
                String userKey = startUserType + ":" + user.getId();
                result.put(userKey, user);
            }
        }
        return result;
    }

    /**
     * 根据用户体系以及用户id加载用户信息
     *
     * @param startUserType 用户体系
     * @param userId        用户id
     * @return
     */
    public JSONObject getUserByIdToJson(String startUserType, String userId) {
        StartBaseUser user = getUserById(startUserType, userId);
        if (user == null) return null;
        return (JSONObject) JSONObject.from(user);
    }

    /**
     * 根据用户体系以及用户id加载用户信息
     *
     * @param startUserType 用户体系
     * @param ids           用户id
     * @param <T>
     * @return
     */
    public <T extends StartBaseUser> List<T> getByUserIds(String startUserType, Collection<? extends Serializable> ids) {
        UserManageInfoService userInfoService = getUserInfoService(startUserType);
        if (userInfoService == null) {
            return null;
        }
        List<T> byUserIds = userInfoService.getByUserIds(ids);
        if (byUserIds == null) return null;
        List<T> result = new ArrayList<>();
        for (Object o : byUserIds) {
            result.add((T) o);
        }
        return result;
    }

    /**
     * 根据用户details 加载用户信息
     *
     * @param details 用户details
     * @param <T>
     * @return
     */
    public <T extends StartBaseUser> T getUserByUserDetails(BaseUserDetails details) {
        UserManageInfoService userInfoService = getUserInfoService(details.getStartUserType());
        if (userInfoService == null) {
            return null;
        }
        StartBaseUser startBaseUser = userInfoService.getByUserId(details.getUserId());
        if (startBaseUser == null) return null;
        return (T) startBaseUser;
    }

    public List<StartDicData> getDictData() {
        return userManageInfoServiceMap.values()
                .stream().map(e -> {
                    StartDicData startDicData = new StartDicData();
                    startDicData.setLabel(e.getLoadUserTypeLabel());
                    startDicData.setValue(e.getLoadUserType());
                    return startDicData;
                }).collect(Collectors.toList());

    }
}
